package com.zsrd.system.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zsrd.auth.core.UserInfoUtil;
import com.zsrd.core.response.ResponseSupport;
import com.zsrd.system.domain.SysMenu;
import com.zsrd.system.domain.dto.UserMenuDto;
import com.zsrd.system.mapper.SysMenuMapper;
import com.zsrd.system.service.SysMenuService;
import com.zsrd.system.service.SysRoleMenuService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@RestController
@RequestMapping("/system/menuManage")
public class MenuController {

    @Autowired
    private SysMenuService sysMenuService;

    @Autowired
    private SysRoleMenuService sysRoleMenuService;



    @Autowired
    private SysMenuMapper sysMenuMapper;
    /**
     * 菜单列表导航栏
     *
     * @return
     */
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public ResponseSupport list() {
        //  获取当前用户信息
        Map<String, Object> userinfo = UserInfoUtil.userinfo();
        Object userId = userinfo.get("userId");
        // 获取用户对应的权限的菜单的所有信息
        List<UserMenuDto> sysMenus = sysRoleMenuService.getRole(userId);

        // 将数据转换成 Map，方便查找
        Map<Long, UserMenuDto> dataMap = new HashMap<>();
        for (UserMenuDto data : sysMenus) {
            dataMap.put(data.getMenuId(), data);
        }

        // 获取没有父级的数据
        List<UserMenuDto> result = getRootData(sysMenus, dataMap);
        for (UserMenuDto userMenuDto : result) {
            List<UserMenuDto> allParentsById = sysMenuMapper.findAllParentsById(userMenuDto.getMenuId());
            for (UserMenuDto userMenuDto1 : allParentsById) {
                sysMenus.add(userMenuDto1);
            }
        }

        List<UserMenuDto> distinctList = sysMenus.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(UserMenuDto::getMenuId))),
                        ArrayList::new
                ));


//        Map<Long, List<UserMenuDto>> groupMap = distinctList.stream().collect(Collectors.groupingBy(UserMenuDto::getParentMenuId));
//        sysMenus.forEach(userMenuDto-> {
//            userMenuDto.setItem(groupMap.get(userMenuDto.getMenuId()));
//        });
//        List<UserMenuDto> collect = distinctList.stream().filter(userMenuDto-> userMenuDto.getParentMenuId().equals(0L)).collect(Collectors.toList());
//        return ResponseSupport.success(collect);
        return ResponseSupport.success(formatDataTree(distinctList));
    }


    // 获取没有父级的数据
    private static List<UserMenuDto> getRootData(List<UserMenuDto> dataList, Map<Long, UserMenuDto> dataMap) {
        List<UserMenuDto> result = new ArrayList<>();
        for (UserMenuDto data : dataList) {
            UserMenuDto parent = dataMap.get(data.getParentMenuId());
            if (parent == null) { // 如果找不到父节点，则添加到结果集合中
                result.add(data);
            }
        }
        return result;
    }



    /**
     * 删除菜单
     *
     * @return 0代表存在 2 删除
     */
    @RequestMapping(value = "delete", method = RequestMethod.POST)
    @ApiOperation(value = "删除", notes = "删除")
    public ResponseSupport delete(@RequestBody SysMenu sysMenu) {
        sysMenu.setDelFlag(2);
        sysMenu.setUpdateTime(new Date());
        boolean b = sysMenuService.updateById(sysMenu);
        if (b == false) {
            return ResponseSupport.fail("删除失败");
        }
        return ResponseSupport.success(b);
    }

    /**
     * 新增菜单
     *
     * @param sysMenu
     * @return
     */
    @RequestMapping(value = "save", method = RequestMethod.POST)
    @ApiOperation(value = "新增", notes = "新增")
    public ResponseSupport saveOrUpdate(@RequestBody SysMenu sysMenu) {
        // 如果menuId = 0 新增
        long menuId = sysMenu.getMenuId();
        String id = String.valueOf(menuId);
        if (StrUtil.equals(id, "0")) {
            // 新增
            sysMenu.setCreateTime(new Date());
            sysMenu.setUpdateTime(new Date());
            sysMenu.setDelFlag(0);
            sysMenuService.save(sysMenu);
            return ResponseSupport.success();
        } else {
            //修改
            sysMenu.setUpdateTime(new Date());
            boolean b = sysMenuService.updateById(sysMenu);
            if (b == false) {
                return ResponseSupport.fail("修改失败");
            }
            return ResponseSupport.success(b);
        }
    }

    /**
     * 树的模糊查询
     *
     * @param sysMenu
     * @return
     */
    @RequestMapping(value = "/query", method = RequestMethod.POST)
    public ResponseSupport query(@RequestBody SysMenu sysMenu) {
        // 模糊查询
        List<SysMenu> sysMenus = sysMenuService.listByTree(sysMenu);
        //collect1里面的数据重新递归
        // 0存在 2删除 并且进行排序
        Stream<SysMenu> sysMenuStream = sysMenus.stream().filter(item -> item.getDelFlag().equals(0))
                .sorted(Comparator.comparingLong(SysMenu::getOrderNum));
        //返回一个stream流方式通过.map方法将list里面的值赋值进去然后返回一个新的list集合
        List<SysMenu> collect2 = sysMenuStream.map(adminSysMenu -> {
            //将上面list查寻的数据调用下面递归的方法依次进行 从0开始 到结束 才退出返回一个新的list
            adminSysMenu.setChildren(getLeafByName(sysMenus, adminSysMenu));
            return adminSysMenu;
        }).sorted(Comparator.comparingLong(SysMenu::getOrderNum)).collect(Collectors.toList());
        //查看这个集合里相同的元素
        List<SysMenu> collect1 = Stream.concat(collect2.stream(), sysMenus.stream())
                .distinct()
                .collect(Collectors.toList());
        //删除多余元素
        for (int i = 0; i < collect1.size(); i++) {
            SysMenu sysMenu2 = collect1.get(i);
            List<SysMenu> children = sysMenu2.getChildren();
            if (CollectionUtil.isNotEmpty(children)) {
                for (SysMenu child : children) {
                    collect2.remove(child);
                }
            }
        }
        return ResponseSupport.success(collect2);
    }

    /**
     * 处理传过来的数据并且进行循环set进他的子集(树)
     *
     * @param sysAreaCodes
     * @param item
     * @return
     */
    private List<SysMenu> getLeafByName(List<SysMenu> sysAreaCodes, SysMenu item) {
        Stream<SysMenu> adminSysMenuStream = sysAreaCodes.stream()
                .filter(items -> items.getParentMenuId() == (item.getMenuId()))
                .filter(items -> items.getDelFlag().equals(0));
        //如果相等就进入里面 将这条数据set进去
        List<SysMenu> collect = adminSysMenuStream.map(adminSysMenu -> {
            adminSysMenu.setChildren(getLeafByName(sysAreaCodes, adminSysMenu));
            //然后返回 一直到没有了以后才返回一次list
            return adminSysMenu;
        }).collect(Collectors.toList());

        return collect;
    }


    /**
     * 菜单回显树接口
     *
     * @return
     */
    @RequestMapping(value = "/menuTree", method = RequestMethod.GET)
    public ResponseSupport menuTree() {
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysMenu::getDelFlag, 0);
        wrapper.orderByAsc(SysMenu::getOrderNum);
        List<SysMenu> sysMenus = sysMenuService.list(wrapper);
        if (CollectionUtil.isNotEmpty(sysMenus)) {
            // 树形结构转换
            TreeNodeConfig config = new TreeNodeConfig();
            config.setIdKey("menuId");//默认为id可以不设置
            config.setParentIdKey("parentMenuId");//默认为parentId可以不设置
            //config.setDeep(4);//最大递归深度
            config.setWeightKey("orderNum");//排序字段
            List<Tree<Long>> build = TreeUtil.build(sysMenus, 0L, config, (object, tree) -> {
                tree.setId(object.getMenuId());
                tree.setParentId(object.getParentMenuId());
                tree.setWeight(object.getOrderNum());
                tree.putExtra("value", object.getMenuId());
                tree.putExtra("label", object.getMenuName());
            });
            return ResponseSupport.success(build);
        }
        return ResponseSupport.fail("查询失败");

    }

    /**
     * 菜单列表导航栏
     *
     * @return
     */
    @RequestMapping(value = "/list2", method = RequestMethod.GET)
    public ResponseSupport list2() {
        //  获取当前用户信息
        Map<String, Object> userinfo = UserInfoUtil.userinfo();
        Object userId = userinfo.get("userId");
        // 获取用户对应的权限的菜单的所有信息
        List<UserMenuDto> sysMenus = sysRoleMenuService.getRole(userId);
        /**
         * 查出所有父id 然后把父id塞进去 看有没有选中子集 没有就把父id删除
         */
        List<UserMenuDto> pids = sysMenuService.selectParentId();
        List<UserMenuDto> pList = new ArrayList<>();
        pList.addAll(pids);

        // 查找所有父id的对象
        for (UserMenuDto s : pids) {
            boolean breakout = true; //是否终止外部循环的标记
            // 遍历上面用户对应的菜单
            for (UserMenuDto sysMenu : sysMenus) {
                // 判断这个父id下有没有选中得子集
                // 如果它有子集 跳出循环
                if (s.getMenuId().longValue() == sysMenu.getParentMenuId().longValue()) {
                    breakout = false;//终止外部循环的标记设置为true
                    break;
                }
            }
            // 循环正常结束时。没找到子集元素 删除父级
            //判断是否终止外部循环
            if (breakout) {
                // 在这个循环结束后仍然没找到它得子集 删除父级
                pList.remove(s);
            }
        }
        // 写一个递归 pids里面有没有自己递归的东西  100 0
        List<UserMenuDto> addList = new ArrayList<>();
        for (UserMenuDto p : pList) {
            // 父id的集合
            List<UserMenuDto> ids = new ArrayList<>();
            treeMenuList(pids, p.getParentMenuId(),ids);
            if (ids.size() > 0) {
                addList.addAll(ids);
            }
        }
        pList.addAll(addList);
        sysMenus.addAll(pList);
        if (sysMenus.size() == 0) {
            return ResponseSupport.fail("没有对应权限");
        }

        return ResponseSupport.success(formatDataTree(sysMenus));
    }

    /**
     * 递归方法
     */
    /*
     查询我这条数的所有父节点集合
     */
    public static void treeMenuList(List<UserMenuDto> menuList, Long pid,List<UserMenuDto> ids) {
        for (UserMenuDto mu : menuList) {
            if (mu.getMenuId().longValue() == pid.longValue()) {
                ids.add(mu);
                treeMenuList(menuList, mu.getParentMenuId(),ids);
            }
        }
    }


    private List<Tree<Long>>  formatDataTree(List<UserMenuDto> sysMenus){
        List<Tree<Long>> build = null;
        for (int i = 0; i < sysMenus.size(); i++) {
            UserMenuDto sysMenu = sysMenus.get(i);
            HashMap<Object, Object> meta = new HashMap<>();
            meta.put("icon", sysMenu.getIcon());
            long isFull = sysMenu.getIsFull();
            Boolean s = isFull == 0 ? false : true;
            meta.put("isFull", s);
            long isKeepAlive = sysMenu.getIsKeepAlive();
            Boolean ka = isKeepAlive == 0 ? false : true;
            meta.put("isKeepAlive", ka);
            long isFrame1 = sysMenu.getIsFrame();
            Boolean f = isFrame1 == 0 ? false : true;
            meta.put("isFrame", f);
            long isHide1 = sysMenu.getIsHide();
            Boolean h = isHide1 == 0 ? false : true;
            meta.put("isHide", h);
            String name = sysMenu.getMenuName();
            meta.put("title", name);
            sysMenu.setMeta(meta);
        }

        // 树形结构转换
        TreeNodeConfig config = new TreeNodeConfig();
        config.setIdKey("menuId");//默认为id可以不设置
        config.setParentIdKey("parentMenuId");//默认为parentId可以不设置
        config.setChildrenKey("children");
        config.setWeightKey("orderNum"); // 根据字段进行排序

        build = TreeUtil.build(sysMenus, 0L, config, (object, tree) ->

        {
            tree.setId(object.getMenuId());
            tree.setParentId(object.getParentMenuId());
            tree.setName(object.getName());
            tree.setWeight(object.getOrderNum());
            tree.putExtra("component", object.getComponent());
            tree.putExtra("path", object.getPath());
            tree.putExtra("meta", object.getMeta());
        });
        return build;
    }
}









